package com.we.es.client;

import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import com.uxuexi.core.common.util.ExceptionUtil;
import com.uxuexi.core.common.util.Util;
import com.we.es.query.DefaultResponseHandler;
import com.we.es.query.SearchResult;
import com.we.es.support.ElaticSearchHelper;
import com.we.es.support.IndexHelper;

/**
 * 提供搜索相关的方法
 * <p>
 * 注意:搜索分为两种，一种是分词形式的全文检索(Full Text),另外一种是精确匹配的搜索.
 * 一，在elasticsearch中使用全文检索有如下方式:
 * 1，MatchQueryBuilder  单字段匹配的全文检索。
 * 2，MultiMatchQueryBuilder  多字段匹配。
 * 3，CommonTermsQueryBuilder
 * 4，SimpleQueryStringBuilder 简单字符串查询
 * 5，QueryStringQueryBuilder  高级用法，支持and or not 等查询语法
 * 参见官方文档：https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.2/java-full-text-queries.html
 * 
 * 二，使用精确查询
 * TermQueryBuilder
 * 
 * @author 朱晓川
 */
public class EsSearchUtil {

	private static final Log log = Logs.get();

	/**
	 * 超时时间
	 */
	private static final int TIME_OUT_SECONDS = 60;

	/**
	 * 使用关键字搜索,带分页(全文检索)
	 *
	 * @param keywords     查询关键字   
	 * @param entityClazz  要返回的实体类型
	 * @param pageNo      当前页
	 * @param pageSize     每页记录数
	 */
	public static SearchResult searchFullText(String keywords, Class<?> entityClazz, int pageNo, int pageSize) {
		if (Util.isEmpty(entityClazz))
			throw ExceptionUtil.pEx("请指定查询实体");

		String q = keywords;
		if (StringUtils.isEmpty(q))
			q = "*";

		String[] indexedFs = IndexHelper.getIndexedFieldsArr(entityClazz);
		MultiMatchQueryBuilder query = QueryBuilders.multiMatchQuery(q, indexedFs);
		String indexName = entityClazz.getSimpleName().toLowerCase();
		SearchRequestBuilder search = makeSearchRequestBuilder(indexName, IndexHelper.DEFAULT_TYPE).setQuery(query)
				//设置60秒超时
				.setTimeout(TimeValue.timeValueSeconds(TIME_OUT_SECONDS)).setFrom((pageNo - 1) * pageSize)
				.setSize(pageSize).setSearchType(SearchType.DEFAULT);

		//设置高亮显示  
		String[] hfields = IndexHelper.getHighLightFields(entityClazz);
		if (!Util.isEmpty(hfields)) {
			HighlightBuilder hlBuilder = new HighlightBuilder().requireFieldMatch(false);
			hlBuilder.preTags("<span style=\"color:red\">");
			hlBuilder.postTags("</span>");
			for (String hname : hfields) {
				hlBuilder.field(hname, 0);
			}
			search.highlighter(hlBuilder);
		}

		log.debug("---------------------search--------------------------");
		log.debug(search.toString());
		SearchResponse response = search.execute().actionGet();
		DefaultResponseHandler handler = new DefaultResponseHandler(response, entityClazz);
		return handler.transfer();
	}

	/**
	 * 创建查询构建器
	 * 
	 * @param indexName
	 * @return
	 */
	private static SearchRequestBuilder makeSearchRequestBuilder(String indexName, String indexType) {
		return ElaticSearchHelper.getClient().prepareSearch(indexName).setTypes(indexType);
	}

}